package com.Artificialintelligence.web.controller.common;

import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import com.Artificialintelligence.common.annotation.Log;
import com.Artificialintelligence.common.annotation.RepeatSubmit;
import com.Artificialintelligence.common.constant.Constants;
import com.Artificialintelligence.common.core.domain.AjaxResult;
import com.Artificialintelligence.common.core.domain.entity.SysUser;
import com.Artificialintelligence.common.core.domain.model.LoginUser;
import com.Artificialintelligence.common.core.service.LogininforService;
import com.Artificialintelligence.common.core.service.TokenService;
import com.Artificialintelligence.common.enums.BusinessType;
import com.Artificialintelligence.common.enums.CaptchaType;
import com.Artificialintelligence.common.utils.*;
import com.Artificialintelligence.common.utils.reflect.ReflectUtils;
import com.Artificialintelligence.common.utils.spring.SpringUtils;
import com.Artificialintelligence.framework.config.properties.CaptchaProperties;
import com.Artificialintelligence.system.domain.SysAuthUser;
import com.Artificialintelligence.system.domain.SysNotice;
import com.Artificialintelligence.system.domain.bo.SysAuthUserBo;
import com.Artificialintelligence.system.mapper.SysNoticeMapper;
import com.Artificialintelligence.system.service.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthGiteeRequest;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 验证码操作处理
 *
 * @author ruoyi
 */
@Slf4j
@RestController
public class CaptchaController {

    @Autowired
    private CaptchaProperties captchaProperties;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private ISysAuthUserService sysAuthUserService;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private LogininforService asyncService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private SysNoticeMapper sysNoticeMapper;

    /**
     * 生成验证码
     */
    @GetMapping("/captchaImage")
    public AjaxResult getCode() {
        Map<String, Object> ajax = new HashMap<>();
        boolean captchaOnOff = configService.selectCaptchaOnOff();
        ajax.put("captchaOnOff", captchaOnOff);
        if (!captchaOnOff) {
            return AjaxResult.success(ajax);
        }
        // 保存验证码信息
        String uuid = IdUtil.simpleUUID();
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
        // 生成验证码
        CaptchaType captchaType = captchaProperties.getType();
        boolean isMath = CaptchaType.MATH == captchaType;
        Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
        CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);
        AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
        captcha.setGenerator(codeGenerator);
        captcha.createCode();
        String code = isMath ? getCodeResult(captcha.getCode()) : captcha.getCode();
        RedisUtils.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
        ajax.put("uuid", uuid);
        ajax.put("img", captcha.getImageBase64());
        return AjaxResult.success(ajax);
    }

    private String getCodeResult(String capStr) {
        int numberLength = captchaProperties.getNumberLength();
        int a = Convert.toInt(StringUtils.substring(capStr, 0, numberLength).trim());
        char operator = capStr.charAt(numberLength);
        int b = Convert.toInt(StringUtils.substring(capStr, numberLength + 1, numberLength + 1 + numberLength).trim());
        switch (operator) {
            case '*':
                return Convert.toStr(a * b);
            case '+':
                return Convert.toStr(a + b);
            case '-':
                return Convert.toStr(a - b);
            default:
                return StringUtils.EMPTY;
        }
    }

//	/**
//	 * 获取授权链接并跳转到第三方授权页面
//	 */
//	@GetMapping("/giteerender")
//	public void renderAuth(HttpServletResponse response) throws IOException {
//		AuthRequest authRequest =  AuthRequestUtil.getAuthRequest();
//        response.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));
//	}

    /**
	 * 获取授权链接并跳转到第三方授权页面--码云
	 */
	@GetMapping("/giteerender")
	public AjaxResult renderAuth() {
        AuthRequest authRequest = AuthRequestUtil.getAuthRequest();
        String token = AuthStateUtils.createState();
        //生成gitee的授权url
        String authorizeUrl = authRequest.authorize(token);
        //将这个url返回给前端Vue
        //由Vue去执行 授权页
        Map<String, String> map = new HashMap<>();
        map.put("url", authorizeUrl);
        return AjaxResult.success(map);
    }

    /**
     * 获取授权链接并跳转到第三方授权页面--支付宝
     */
    @GetMapping("/alipay")
    public AjaxResult alipay() {
        AuthRequest authRequest = AuthRequestUtil.getAuthAlipayRequest();
        //生成gitee的授权url
        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
        //将这个url返回给前端Vue
        //由Vue去执行 授权页
        Map<String, String> map = new HashMap<>();
        map.put("url", authorizeUrl);
        return AjaxResult.success(map);
    }

    /**
     * 获取授权链接并跳转到第三方授权页面--qq
     */
    @GetMapping("/qqAuth")
    public AjaxResult qqAuth() {
        AuthRequest authRequest = AuthRequestUtil.getAuthQqRequest();
        //生成gitee的授权url
        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
        //将这个url返回给前端Vue
        //由Vue去执行 授权页
        Map<String, String> map = new HashMap<>();
        map.put("url", authorizeUrl);
        return AjaxResult.success(map);
    }


    @GetMapping("/loginnotice")
    public AjaxResult loginnotice() {
        QueryWrapper<SysNotice> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", "0");
        List<SysNotice> sysNotice = sysNoticeMapper.selectList(queryWrapper);
        Map<String, Object> map = new HashMap<>();
        map.put("SysNotice",sysNotice);
        return AjaxResult.success(map);
    }

    /**
     * 用户在确认第三方平台授权（登录）后， 第三方平台会重定向到该地址，并携带code、state等参数 token
     *
     * @param callback 第三方回调时的入参
     * @return 第三方平台的用户信息
     */
    @RequestMapping("/callback")
    public void login(AuthCallback callback, HttpServletResponse response) throws IOException {
        AuthRequest authRequest = AuthRequestUtil.getAuthRequest();
        HttpServletRequest request = ServletUtils.getRequest();
        String token = null;
        AuthResponse login = authRequest.login(callback);
        AuthUser authUser = (AuthUser) login.getData();
        SysAuthUser sysAuthUser = sysAuthUserService.getOne(new LambdaQueryWrapper<SysAuthUser>().eq(SysAuthUser::getUuid, authUser.getUuid()).eq(SysAuthUser::getSource, authUser.getSource()));
        //查询本机用户
        if (sysAuthUser != null && sysAuthUser.getUserId() != null) {
            SysUser sysUser = sysUserService.getById(sysAuthUser.getUserId());
            LoginUser loginUser = createLoginUser(sysUser);
            asyncService.recordLogininfor(sysUser.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
            recordLoginInfo(loginUser.getUserId());
            // 生成token
            token = tokenService.createToken(loginUser);
            response.sendRedirect("http://www.yunzhimuo.com/register?token=" + token);
        } else {
            sysAuthUser = new SysAuthUser();
            BeanUtils.copyProperties(authUser, sysAuthUser);
            sysAuthUser.setUserName(authUser.getNickname());
            sysAuthUser.setLoginName(authUser.getUsername());
            boolean lean = sysAuthUserService.saveOrUpdate(sysAuthUser);
            if(lean) {
                response.sendRedirect("http://www.yunzhimuo.com/register?uuid=" + authUser.getUuid() + "&source=" + authUser.getSource());
            }else {
                response.sendRedirect("http://www.yunzhimuo.com/login?k="+500);
            }
        }
    }

    /**
     * 用户在确认第三方平台授权（登录）后， 第三方平台会重定向到该地址，并携带code、state等参数 token
     *
     * @param callback 第三方回调时的入参
     * @return 第三方平台的用户信息
     */
    @RequestMapping("/alicallback")
    public void alilogin(AuthCallback callback, HttpServletResponse response) throws IOException {
        AuthRequest authRequest = AuthRequestUtil.getAuthAlipayRequest();
        HttpServletRequest request = ServletUtils.getRequest();
        String token = null;
        AuthResponse login = authRequest.login(callback);
        AuthUser authUser = (AuthUser) login.getData();
        SysAuthUser sysAuthUser = sysAuthUserService.getOne(new LambdaQueryWrapper<SysAuthUser>().eq(SysAuthUser::getUuid, authUser.getUuid()).eq(SysAuthUser::getSource, authUser.getSource()));
        //查询本机用户
        if (sysAuthUser != null && sysAuthUser.getUserId() != null) {
            SysUser sysUser = sysUserService.getById(sysAuthUser.getUserId());
            LoginUser loginUser = createLoginUser(sysUser);
            asyncService.recordLogininfor(sysUser.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
            recordLoginInfo(loginUser.getUserId());
            // 生成token
            token = tokenService.createToken(loginUser);
            response.sendRedirect("http://www.yunzhimuo.com/register?token=" + token);
        } else {
            sysAuthUser = new SysAuthUser();
            BeanUtils.copyProperties(authUser, sysAuthUser);
            sysAuthUser.setUserName(authUser.getNickname());
            sysAuthUser.setLoginName(authUser.getUsername());
            boolean lean = sysAuthUserService.saveOrUpdate(sysAuthUser);
            if(lean) {
                response.sendRedirect("http://www.yunzhimuo.com/register?uuid=" + authUser.getUuid() + "&source=" + authUser.getSource());
            }else {
                response.sendRedirect("http://www.yunzhimuo.com/login?k="+500);
            }
        }
    }

    /**
     * 用户在确认第三方平台授权（登录）后， 第三方平台会重定向到该地址，并携带code、state等参数 token
     *
     * @param callback 第三方回调时的入参
     * @return 第三方平台的用户信息
     */
    @PostMapping("/Qqcallback")
    public void Qqlogin(@RequestBody AuthCallback callback, HttpServletResponse response) throws IOException {
        AuthRequest authRequest = AuthRequestUtil.getAuthQqRequest();
        HttpServletRequest request = ServletUtils.getRequest();
        String token = null;
        AuthResponse login = authRequest.login(callback);
        AuthUser authUser = (AuthUser) login.getData();
        SysAuthUser sysAuthUser = sysAuthUserService.getOne(new LambdaQueryWrapper<SysAuthUser>().eq(SysAuthUser::getUuid, authUser.getUuid()).eq(SysAuthUser::getSource, authUser.getSource()));
        //查询本机用户
        if (sysAuthUser != null && sysAuthUser.getUserId() != null) {
            SysUser sysUser = sysUserService.getById(sysAuthUser.getUserId());
            LoginUser loginUser = createLoginUser(sysUser);
            asyncService.recordLogininfor(sysUser.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
            recordLoginInfo(loginUser.getUserId());
            // 生成token
            token = tokenService.createToken(loginUser);
            response.sendRedirect("http://www.yunzhimuo.com/register?token=" + token);
        } else {
            sysAuthUser = new SysAuthUser();
            BeanUtils.copyProperties(authUser, sysAuthUser);
            sysAuthUser.setUserName(authUser.getNickname());
            sysAuthUser.setLoginName(authUser.getUsername());
            boolean lean = sysAuthUserService.saveOrUpdate(sysAuthUser);
            if(lean) {
                response.sendRedirect("http://www.yunzhimuo.com/register?uuid=" + authUser.getUuid() + "&source=" + authUser.getSource());
            }else {
                response.sendRedirect("http://www.yunzhimuo.com/login?k="+500);
            }
        }
    }

    public LoginUser createLoginUser(SysUser user) {
        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
    }

    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(ServletUtils.getClientIP());
        sysUser.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(sysUser);
    }

    /**
     * 第三方授权绑定账号
     */
    @PostMapping("/adduser")
    public AjaxResult adduser(@Validated @RequestBody SysAuthUserBo bo) {
        // 查询用户
        SysUser sysUser1 = new SysUser();
        sysUser1.setPassword(bo.getPassword());
        sysUser1.setUserName(bo.getUser());
        bo.setUserPass(bo.getPassword());
        SysUser sysUser = sysUserService.selectUserByUserNamePass(sysUser1);
        if (sysUser != null && sysUser.getUserId() != 0L) {
            // 跟新第三方信息
            SysAuthUser sysAuthUser = new SysAuthUser();
            sysAuthUser.setSource(bo.getSource());
            sysAuthUser.setUuid(bo.getUuid());
            sysAuthUser.setUserId(sysUser.getUserId());
//            bo.setUserId(sysUser.getUserId());
            boolean lean = sysAuthUserService.update(sysAuthUser,new QueryWrapper<SysAuthUser>().eq("uuid", bo.getUuid()).eq("source",bo.getSource()));
//            boolean lean = sysAuthUserService.insertByBo(bo);
            if (lean) {
//                sysUser.setUuid(bo.getUuid());
//                sysUserService.updateUser(sysUser);
                return AjaxResult.success("绑定成功,请重新登陆");
            } else {
                return AjaxResult.error("系统错误，绑定失败");
            }
        } else {
            return AjaxResult.error("没有该用户,请认真检测账号或密码是否正确");
        }
    }

}
